Configurações iniciais

Para plotar os mapas eu uso essencialmente estas bibliotecas.

# carrega as bibliotecas principais para processamento e visualizaĂ§Ă£o
library(tidyverse)
# manipulaĂ§Ă£o de shp e visualizaĂ§Ă£o
library(sf)
# leitura de figura em png (para usar o fundo de SP nos mapas)
library(png)
# adiĂ§Ă£o de mais um layer na visualizaĂ§Ă£o com o mesmo tipo (fill, color ou shp...)
library(ggnewscale)
# também uso ggspatial para pegar o fundo da imagem e aplicar a escala
library(ggspatial)
# paleta padrĂ£o
library(viridis)

Configurações de plotagem que uso por padrĂ£o. Dependendo do grĂ¡fico ou mapa Ă© possĂ­vel sobrescrever essas configurações (principalmente adicionar as de temas).

# tamanho padrĂ£o ----
base <- 297 # tamanho base para altura das imagens

# tamanho da fonte e linha proporcional Ă  altura da pĂ¡gina
font.size <- 4.23*ggplot2::.pt # 4.23 mm Ă© mais ou menos 12pt
txt.size <- font.size
title.size <- txt.size*1.2
cap.size <- txt.size*0.8

line.size <- 0.25*ggplot2::.stroke

# sugestĂ£o de proporĂ§Ă£o das dimensões das figuras para salvar
map_dim <- data.frame(map = c(1, 2, 3, 4, 5, 8, 'chart','3_short', 'chart_short'),
                      height = base,
                      width = base/c(1.65, 0.9 ,0.65, 0.55, 0.46, 0.85, 0.45, 0.95, 0.1125))

# definições espaciais ----

# CRS mais usados dos shapefiles que carrego
crsutm <- 32723 # WGS84 UTM 23S
crsutm_sirgas <- 31983 # SIRGAS2000 UTM 23S
crsdegrees <- 4326 # degrees

# delimitaĂ§Ă£o da Ă¡rea de plot espacial em relaĂ§Ă£o a SP ----
# municĂ­pio inteiro
coord_lim <- coord_sf(ylim = c(7346293.52,7413300.44), 
                      xlim = c(314223.75, 360463.96),
                      crs = crsutm) 
# parte do muniĂ­pio
coord_lim_short <- coord_sf(xlim = c(-46.826081, -46.365377), 
                            ylim = c(-23.716492, -23.384091),
                            crs = crsdegrees)

# opções de background ----
## download da base usando ggspatial
## busca no arquivo que criei com tipos de fundos o fundo escolhido
## costumo usar o da ESRI e sempre coloco um caption sobre de onde veio
bg_options <- read.csv2('background_map_tiles.csv', stringsAsFactors = F)
basemap_option <- 'esri-light-gray' # basemap
bg <- bg_options[bg_options$option==basemap_option,]
## a partir do ggspatial, baixo os tiles para montar o fundo e salvar para usar em outros mapas
# p <- ggplot() +
#    ggspatial::annotation_map_tile(type = bg$link, 
#                                   zoom = 12,
#                                   quiet = T,
#                                   progress = 'text')+ 
#    coord_lim_short +
#    theme_void()
# ggsave('data/basemap_short_esri_light_gray_12.png', 
#        p, dpi = 500, width = 7, height = 4, 
#        units = "in", type = 'cairo-png')

# leitura do fundo com SP cortada
basemap <- png::readPNG('data/basemap_short_esri_light_gray_12.png')
ggbasemap_short <- grid::rasterGrob(basemap, interpolate = T)
# leitura do fundo com SP inteira
basemap <- png::readPNG('data/basemap_esri_light_gray_12.png')
ggbasemap <- grid::rasterGrob(basemap, interpolate = T)
# remove o png
rm(basemap)
gc()
##            used  (Mb) gc trigger   (Mb)  max used   (Mb)
## Ncells  1105919  59.1    2138497  114.3   1684476   90.0
## Vcells 38870477 296.6  189393000 1445.0 227554025 1736.1
# definições de norte e escala ----
norte <-   ggspatial::annotation_north_arrow(location = 'br',
                                             height = unit(.75, "in"),
                                             width = unit(.75, "in"),
                                             pad_y = unit(.75, "cm"),
                                             style = north_arrow_orienteering(
                                               line_width = 1,
                                               line_col = "grey15",
                                               fill = c("white", "grey15"),
                                               text_col = "grey15",
                                               text_family = "",
                                               text_face = NULL,
                                               text_size = 8,
                                               text_angle = 0
                                             )) 

escala <- ggspatial::annotation_scale(location = 'br', 
                                      height = unit(0.25, "cm"),
                                      bar_cols = c('grey15', 'grey99'), 
                                      line_width = 0.3,
                                      line_col = 'grey15',
                                      text_col = 'grey15')

# temas padrĂ£o para grĂ¡ficos e mapas ----
# estes temas eu coloco logo ao final de todo plot
# padrĂ£o de grĂ¡ficos
theme_chart <- theme_bw() +
  theme(panel.border = element_blank(),
        panel.spacing = unit(2, 'mm'),
        # axis
        axis.line = element_line(color='grey30'),
        axis.ticks = element_line(color='grey30'),
        axis.text = element_text(size = txt.size),
        axis.title = element_text(size = title.size),
        # legend
        legend.position = 'bottom',
        legend.text = element_text(size=txt.size),
        legend.title = element_text(size=title.size),
        legend.spacing.x = unit(.01,"cm"),
        # strip
        strip.background = element_blank(),
        strip.text = element_text(size = title.size),
        # margin
        plot.margin = margin(2, 2, 2, 2, 'mm'))

# padrĂ£o de mapas
theme_map <- theme(
  # axis
  axis.line = element_blank(),
  axis.ticks = element_blank(),
  axis.text = element_blank(),
  axis.title = element_blank(),
  # facet grid
  panel.grid = element_line(color="#CFCED3"),
  panel.spacing = unit(2,'mm'),
  # legend
  legend.position = "bottom",
  legend.box = "horizontal",
  legend.direction = "horizontal",
  legend.spacing = unit(2, "mm"),
  legend.text = element_text(size=txt.size),
  legend.title = element_text(size=title.size),
  # facet
  strip.background = element_blank(), 
  strip.text = element_text(size = title.size),
  # background
  panel.background = element_rect(fill="#CFCED3"),
  plot.background = element_blank(),
  # caption
  plot.caption = element_text(size = cap.size,
                              hjust = 0),
  plot.caption.position = "panel",
  # margin,
  plot.margin = margin(1, 1, 1, 1, 'mm'))

Paleta de cores

# cores para Ă¡gua e para Ă¡reas verdes
colWater <- "#CFCED3" 
colGreen <-  "#E2E7E1"

# cor de ciclovia
ciclovia_cor <- "grey20" # usei esta cor nos plots abaixo para testar o cotraste com as paletas e parece que o Ăºnico problema seria o azul mais escuro

Deixei com duas opções as escalas graduais, uma vermelha (baseada na viridis rocket) e outra azul (baseada na viridis mako), mas Ă© bom vocĂªs conversarem entre si sobre qual vai ser o padrĂ£o que vĂ£o usar (vermelho para quanto mais vermelho, pior, ou azul para piores valores). Para as duas a escala começa deois begin = 0.4 para evitar as cores muito escuras.

Ainda, as paletas sĂ£o uma funĂ§Ă£o que depende da quantidade de cores que querem e da direĂ§Ă£o que querem que comece . O padrĂ£o que deixei Ă© sempre começar da cor mais clara para a mais escura (direction = -1), mas se quiserem que o valor mais baixo comece com a cor mais escura, Ă© sĂ³ colocar direction = 1.

# escala gradual crescente vermelha
pal_red <- function(n, direction = -1){rocket(n, begin = 0.4, direction = direction)}

# paleta crescente azul
pal_blue <- function(n, direction = -1){mako(n, begin = 0.25, direction = direction)}


# demonstraĂ§Ă£o das cores
tibble(x = 1:5,
       y = 1,
       col = pal_blue(5),
       paleta = 'azul') %>% 
  bind_rows(tibble(x = 1:5,
                   y = 1,
                   col = pal_red(5),
                   paleta = 'vermelha, direction = -1')) %>% 
  bind_rows(tibble(x = 1:5,
                   y = 1,
                   col = pal_red(5, direction = 1),
                   paleta = 'vermelha, direction = 1')) %>% 
  ggplot() +
  geom_tile(aes(x, y, fill = col), show.legend = F) +
  geom_text(aes(x, y, label = col), color = ciclovia_cor, angle = 90)+
  scale_fill_manual(values = c(pal_blue(5),pal_red(5),pal_red(5, direction = 1)),
                    breaks = c(pal_blue(5),pal_red(5),pal_red(5, direction = 1)))+
  facet_grid(.~paleta)+
  theme_chart

Para a escala divergente, eu juntei as duas paletas (azul e vermelha) em uma. Existe a possibilidade de trabalhar com nĂºmeros Ă­mpares ou pares de cor.

# escala gradual divergente (junĂ§Ă£o de duas paletas do viridis) - nĂ£o Ă© o ideal para usar
pal_div<- function(n){
  if (n%%2 == 1){ #  n Ă© impar
    n <- (n-1)/2
    div <- c(rocket(n, begin = 0.4, end = 1 - 0.6/n), # paleta vermelha
             "#EBE6D3", # intermediĂ¡ria
             mako(n, begin = 0.25, end = 1-0.75/n, direction = -1)) # paleta azul
  } else{ # n Ă© par e nĂ£o precisa da intermediĂ¡ria
    n <- n/2
    div <- c(rocket(n, begin = 0.4, end=.95), # paleta vermelha
             mako(n, begin = 0.25, direction = -1)) # paleta azul
  }
  div
}

# demonstraĂ§Ă£o das cores
tibble(x = 1:9,
       y = 1,
       col = pal_div(9),
       paleta = "Ă­mpar") %>% 
  bind_rows(tibble(x = 1:10,
                   y = 1,
                   col = pal_div(10),
                   paleta = "par")) %>% 
  ggplot() +
  geom_tile(aes(x, y, fill = col), show.legend = F) +
  geom_text(aes(x, y, label = col), color = ciclovia_cor, angle = 90)+
  scale_fill_manual(values = c(pal_div(9),pal_div(10)),
                    breaks = c(pal_div(9),pal_div(10)),)+
  facet_wrap(.~paleta)+
  theme_chart

Outro ponto importante para ter cuidado com os plots de mapas na cartografia Ă© a quantidade de cores selecionadas. Sempre Ă© melhor trabalhar com faixas ao invĂ©s de gradientes, assim fica mais fĂ¡cil para identificar qual Ă© a cor e o valor referente Ă  Ă¡rea. AlĂ©m disso, tambĂ©m para facilitar a identificaĂ§Ă£o das cores/valores, sugiro trabalhar com menos de 7 categorias (para mim o ideal Ă© 5).

Carregando arquivos

Arquivos base

# outros municĂ­pios alĂ©m de SP para gerar a mĂ¡scara
muni <- sf::st_read("data/shp/Outros_muni-MSP.shp", quiet=T, crs=crsutm) %>% 
  sf::st_transform(crs = crsdegrees) 
massa <- sf::st_read("data/shp/Massa_dagua_MSP.shp", quiet=T, crs = crsutm_sirgas) %>% 
  sf::st_transform(crs = crsdegrees)  
rios <- sf::st_read("data/shp/Rio_MSP.shp", quiet=T, crs=crsutm_sirgas) %>% 
  sf::st_transform(crs = crsdegrees) 
verde <- sf::st_read("data/shp/Verde_MSP.shp", quiet=T, crs=crsutm_sirgas) %>% 
  sf::st_transform(crs = crsdegrees)

Arquivos de interesse. Estou usando uma base de empregos por Zona OD de 2007 que eu tinha pronta aqui de um outro tutorial.

zona_emp <-  sf::st_read("data/Zona2007_empregos.shp") %>% 
  filter(Municipio == 36) # sĂ³ para pegar SP
## Reading layer `Zona2007_empregos' from data source 
##   `D:\OneDrive\Projetos\Freelas\WB\PadronizaĂƒÂ§ĂƒÂ£o de mapas\data\Zona2007_empregos.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 460 features and 8 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 275286.7 ymin: 7337262 xmax: 429138.9 ymax: 7435586
## Projected CRS: UTM_Zone_23_Southern_Hemisphere

Fazendo os mapas

Como havia comentado, tem duas opções de enquadramento dos mapas. O padrĂ£o que uso Ă©:

# mapa padrĂ£o
p <- ggplot() +
  # bg 
  annotation_custom(ggbasemap, xmin=-Inf, xmax = Inf, ymin = -Inf, ymax = Inf) +
  # adicionar o layer de interesse aqui
  #base maps
  geom_sf(data=verde, fill=colGreen, color="transparent") +
  geom_sf(data = massa, fill = colWater, color = colWater, size = line.size/2)  +
  geom_sf(data=rios, color=colWater, size=line.size) +
  geom_sf(data=muni, fill = 'grey40', color = 'transparent', alpha = 0.25) +
  labs(caption = bg$caption) +
  escala +
  norte +
  coord_lim +
  theme_map 

# salvar em alta qualidade
width <- dplyr::filter(map_dim, map=='1')$width # como sĂ³ tem um mapa, coloco 1 em map
ggsave('figuras/mapa_base.png', 
       p, dpi = 500, width = width, height = base, 
       units = "mm", type = 'cairo-png')

# incluindo alguma informaĂ§Ă£o ao mapa base

# separei em dois bds sĂ³ para colocar o exemplo da inclusĂ£o de dois mapas com paletas diferentes em um mesmo plot
df1 <- zona_emp %>% 
  rename(values = empregos) %>% 
  mutate(var = "empregos")

df2 <- zona_emp %>% 
  rename(values = pop) %>% 
  mutate(var = "populaĂ§Ă£o")

p <- ggplot() +
  # bg 
  annotation_custom(ggbasemap, xmin=-Inf, xmax = Inf, ymin = -Inf, ymax = Inf) +
  # adicionar o layer de interesse aqui
  geom_sf(data = df1, aes(fill=values), color = "transparent") +
  scale_fill_stepsn('# de empregos (x1000)',
                    colors = pal_red(5), # nĂºmero de cores deve ser igual ao nĂºmero de breaks
                    n.breaks = 5,
                    labels = function(x){x/1000}, #para deixar na base 1000
                    guide = guide_colorsteps(show.limits=T,
                                             title.position = 'top',
                                             order = 2))+
  # adicionando uma nova camada
  new_scale_fill() +
  geom_sf(data = df2, aes(fill=values), color = "transparent") +
  scale_fill_stepsn('populaĂ§Ă£o (x1000)',
                    colors = pal_blue(5),
                    n.breaks = 5,
                    labels = function(x){x/1000},
                    guide = guide_colorsteps(show.limits=T,
                                             title.position = 'top',
                                             order = 2))+
  #base maps
  geom_sf(data=verde, fill=colGreen, color="transparent") +
  geom_sf(data = massa, fill = colWater, color = colWater, size = line.size/2)  +
  geom_sf(data=rios, color=colWater, size=line.size) +
  geom_sf(data=muni, fill = 'grey40', color = 'transparent', alpha = 0.25) +
  facet_grid(.~var) +
  labs(caption = bg$caption) +
  escala +
  norte +
  coord_lim +
  theme_map 

# salvar em alta qualidade
width <- dplyr::filter(map_dim, map=='2')$width # como tem 2 mapas, coloco 2 em map
ggsave('figuras/mapa_aplicaĂ§Ă£o.png', 
       p, dpi = 500, width = width, height = base, 
       units = "mm", type = 'cairo-png')

Mapa menor

p <- ggplot() +
  # bg 
  annotation_custom(ggbasemap_short, xmin=-Inf, xmax = Inf, ymin = -Inf, ymax = Inf) +
  # adicionar o layer de interesse aqui
  geom_sf(data = df1, aes(fill=values), color = "transparent") +
  scale_fill_stepsn('# de empregos (x1000)',
                    colors = pal_red(5),
                    n.breaks = 5,
                    labels = function(x){x/1000}, #para deixar na base 1000
                    guide = guide_colorsteps(show.limits=T,
                                             title.position = 'top',
                                             order = 2))+
  # adicionando uma nova camada
  new_scale_fill() +
  geom_sf(data = df2, aes(fill=values), color = "transparent") +
  scale_fill_stepsn('populaĂ§Ă£o (x1000)',
                    colors = pal_blue(5),
                    n.breaks = 5,
                    labels = function(x){x/1000},
                    guide = guide_colorsteps(show.limits=T,
                                             title.position = 'top',
                                             order = 2))+
  #base maps
  geom_sf(data=verde, fill=colGreen, color="transparent") +
  geom_sf(data = massa, fill = colWater, color = colWater, size = line.size/2)  +
  geom_sf(data=rios, color=colWater, size=line.size) +
  geom_sf(data=muni, fill = 'grey40', color = 'transparent', alpha = 0.25) +
  facet_grid(.~var) +
  labs(caption = bg$caption) +
  escala +
  norte +
  coord_lim_short +
  theme_map 

# salvar em alta qualidade
width <- dplyr::filter(map_dim, map=='3_short')$width # short nĂ£o tem muitas definições
ggsave('figuras/mapa_aplicaĂ§Ă£o_short.png', 
       p, dpi = 500, width = width, height = base, 
       units = "mm", type = 'cairo-png')

Mapa com escala discreta. Detalhe que as cores na funĂ§Ă£o scale_*_manual entram no atributo values. Diferente da funĂ§Ă£o scale_*_stepsn(), em que as cores entram como colors.

# incluindo alguma informaĂ§Ă£o ao mapa base
set.seed(1)
zonas <- sample(1:320, 15)

p <- ggplot() +
  # bg 
  annotation_custom(ggbasemap, xmin=-Inf, xmax = Inf, ymin = -Inf, ymax = Inf) +
  # adicionar o layer de interesse aqui
  geom_sf(data = filter(zona_emp, Zona07 %in% zonas), aes(fill=Zona07), color = "transparent") +
  scale_fill_manual('algumas zonas',
                    breaks = zonas,
                    values = pal_red(15), 
                    guide = guide_legend(show.limits=T,
                                             title.position = 'top',
                                             order = 2))+
  #base maps
  geom_sf(data=verde, fill=colGreen, color="transparent") +
  geom_sf(data = massa, fill = colWater, color = colWater, size = line.size/2)  +
  geom_sf(data=rios, color=colWater, size=line.size) +
  geom_sf(data=muni, fill = 'grey40', color = 'transparent', alpha = 0.25) +
  labs(caption = bg$caption) +
  escala +
  norte +
  coord_lim +
  theme_map 

# salvar em alta qualidade
width <- dplyr::filter(map_dim, map=='1')$width # como tem 2 mapas, coloco 2 em map
ggsave('figuras/mapa_zonas_discreto.png', 
       p, dpi = 500, width = width, height = base, 
       units = "mm", type = 'cairo-png')